/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.ipti.br.tag.dao;

import org.ipti.br.tag.entity.Organization;
import org.ipti.br.tag.entity.Organization_;
import org.ipti.br.tag.entity.Work;
import org.ipti.br.tag.entity.WorkTopic;
import org.ipti.br.tag.entity.WorkTopic_;
import org.ipti.br.tag.entity.Work_;
import java.io.Serializable;
import java.util.Calendar;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;

/**
 *
 * @author ipti
 */
@Stateless
public class WorkTopicFacade extends AbstractFacade<WorkTopic> implements Serializable {

    @PersistenceContext(unitName = "TAG2PU")
    private EntityManager em;

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    public WorkTopicFacade() {
        super(WorkTopic.class);
    }

    @Override
    public void create(WorkTopic topic) {
        getEntityManager().persist(topic);
        
        if(topic.getFather() != null){
            topic.getFather().getSons().add(topic);
            getEntityManager().merge(topic.getFather());
        }
    }

    @Override
    public void edit(WorkTopic topic) {
        getEntityManager().merge(topic);
    }

    public void createWithoutHash(WorkTopic topic) {
        getEntityManager().persist(topic);
    }
    
    public List<WorkTopic> getNotLeafs() {
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<WorkTopic> cq = cb.createQuery(WorkTopic.class);
        Root<WorkTopic> rt1 = cq.from(WorkTopic.class);
        Root<WorkTopic> rt2 = cq.from(WorkTopic.class);
        
        cq.where(cb.equal(rt2.get(WorkTopic_.father).get(WorkTopic_.id), rt1.get(WorkTopic_.id)));
        cq.distinct(true);
        
        try {
            return getEntityManager().createQuery(cq).getResultList();
        } catch (NoResultException nre) {
            return null;
        }
    }
    
    public List<WorkTopic> getLeafs() {
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<WorkTopic> cq = cb.createQuery(WorkTopic.class);
        Root<WorkTopic> rt = cq.from(WorkTopic.class);
        
        Subquery<Long> subQ = cq.subquery(Long.class);
        Root<WorkTopic> subRT = subQ.from(WorkTopic.class);
        
        subQ.select(cb.count(subRT));
        subQ.where(cb.equal(subRT.get(WorkTopic_.id), rt.get(WorkTopic_.id)));
        
        cq.where(cb.gt(subQ, 0));
        cq.distinct(true);
        
        try {
            return getEntityManager().createQuery(cq).getResultList();
        } catch (NoResultException nre) {
            return null;
        }
    }
    
    public Integer getMaxCode(Organization org) {
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<Integer> cq = cb.createQuery(Integer.class);
        Root<Work> rt = cq.from(Work.class);
        Join<Work,WorkTopic> topic = rt.join(Work_.topic);
        
        cq.select(cb.max(topic.get(WorkTopic_.code)));
        
        cq.where(cb.equal(rt.get(Work_.organization).get(Organization_.id), org.getId()));
        
        try {
            return getEntityManager().createQuery(cq).getSingleResult();
        } catch (NoResultException nre) {
            return null;
        }
    }
    
    public WorkTopic getByCode(Organization org, int code) {
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<WorkTopic> cq = cb.createQuery(WorkTopic.class);
        Root<WorkTopic> rt = cq.from(WorkTopic.class);
        Root<Work> rt1 = cq.from(Work.class);
        
        Predicate p1 = cb.equal(rt.get(WorkTopic_.code), code);
        Predicate p2 = cb.equal(rt.join(WorkTopic_.top).get(WorkTopic_.id), rt1.get(Work_.topic).get(WorkTopic_.id));
        Predicate p3 = cb.equal(rt1.get(Work_.organization).get(Organization_.id), org.getId());
        cq.where(p1,p2,p3);
        
        try {
            return getEntityManager().createQuery(cq).getSingleResult();
        } catch (NoResultException nre) {
            return null;
        }
    }
    
//    public Integer getLastRootCode(Organization org){
//        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
//        CriteriaQuery<Integer> cq = cb.createQuery(Integer.class);
//        Root<Work> rt = cq.from(Work.class);
//        Join<Work,WorkTopic> topic = rt.join(Work_.topic);
//        
//        cq.select(cb.max(topic.get(WorkTopic_.code)));
//        
//        Predicate p1 = cb.equal(rt.get(Work_.organization).get(Organization_.id), org.getId());
//        cq.where(p1);
//        
//        try {
//            return getEntityManager().createQuery(cq).getSingleResult();
//        } catch (NoResultException nre) {
//            return null;
//        }
//    }
    
//    public WorkTopic getRootTopic(Integer code) {
//        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
//        CriteriaQuery<WorkTopic> cq = cb.createQuery(WorkTopic.class);
//        Root<Work> rt = cq.from(Work.class);
//        Join<Work,WorkTopic> topic = rt.join(Work_.topic);
//        
//        cq.select(topic);
//        
//        cq.where(cb.equal(topic.get(WorkTopic_.code), code));
//        
//        try {
//            return getEntityManager().createQuery(cq).getSingleResult();
//        } catch (NoResultException nre) {
//            return null;
//        }
//    }

    public List<WorkTopic> modifiedTopics(Calendar initialDate, Calendar finalDate, Long serialNumber) {
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<WorkTopic> cq = cb.createQuery(WorkTopic.class);
        Root<WorkTopic> from = cq.from(WorkTopic.class);
        Predicate predicate1 = cb.notEqual(from.get(WorkTopic_.serialNumber), serialNumber);
        Predicate predicate2 = cb.greaterThanOrEqualTo(from.get(WorkTopic_.lastModified), initialDate);
        Predicate predicate3 = cb.lessThan(from.get(WorkTopic_.lastModified), finalDate);
        cq.where(cb.and(predicate1, predicate2, predicate3));

        return getEntityManager().createQuery(cq).getResultList();
    }
}
